#pragma once

// -----------------------------------------------------------------------------
// File: Win32.IO.TextFile.h

#include <shlwapi.h>
#include "Win32.Diagnostics.Result.h"
#include "Win32.String.h"
#include "Win32.IO.TextBuffer.h"
#include "Win32.IO.File.h"

namespace Kif
{
namespace Win32
{
namespace IO
{

template<typename T>
class TextBuffer;

/// <summary>information about an open file</summary>
class TextFile
{
private:

   TCHAR *lastErrorMessage;
   Kif::Win32::Diagnostics::Result lastResult;

   HANDLE   hFile;             // file handler

   /// <summary>Open given file for read and write</summary>
   /// <param name="path">file path name</param>
   /// <param name="dwDesiredAccess">desired access</paarm>
   /// <param name="dwShareMode">shared mode</paarm>
   /// <param name="dwCreationDisposition">creation disposition</paarm>
   /// <return>true is returned if operation was completed</returns>
   inline bool Open(
      TCHAR *path,
      DWORD dwDesiredAccess,
      DWORD dwShareMode,
      DWORD dwCreationDisposition)
   {
      lastResult.Clear();
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }

      // open file for read and write
      hFile = CreateFile(path,
         dwDesiredAccess,                     // desired access
         dwShareMode,                         // shared access
         NULL,                                // specify default security
         dwCreationDisposition,               // creation disposition
         FILE_ATTRIBUTE_NORMAL |
         FILE_FLAG_SEQUENTIAL_SCAN,           // flags and attributes
         NULL);                               // template file

      if (hFile == INVALID_HANDLE_VALUE)
         lastResult.ErrorNo = GetLastError();

      return(hFile != INVALID_HANDLE_VALUE);
   }  // end of OpenReadWrite

public:

   inline Kif::Win32::Diagnostics::Result *GetLastResult()
   {
      return(&lastResult);
   }  // end of GetLastResult

   /// <summary>close and release resources</summary>
   void Close()
   {
      if (hFile != INVALID_HANDLE_VALUE)
         CloseHandle(hFile);
      hFile = INVALID_HANDLE_VALUE;
      lastResult.Clear();
   }  // end of Close

   // --------------------------------------------------------------------------

   TextFile()
   {
      hFile = INVALID_HANDLE_VALUE;
   }  // end of TextFile (ctor)

  ~TextFile()
   {
      Close();
   }  // end of TextFile (dtor)

   // --------------------------------------------------------------------------

   /// <summary>Create given file. The file will only be created you will need
   /// to open it later.</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool Create(TCHAR *path)
   {
      // open file for read and write
      bool done = Open(path,
         FILE_SHARE_DELETE |
         GENERIC_READ | GENERIC_WRITE,        // desired access
         FILE_SHARE_READ | FILE_SHARE_WRITE,  // shared access
         CREATE_ALWAYS);                      // creation disposition

      // on creation always close the file
      if (done)
         Close();
      return(done);
   }  // end of Create

   inline bool Create(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(Create(path->GetBuffer()));
   }  // end of Create

   inline bool Create(Kif::Win32::String &path)
   {
      return(Create(path.GetBuffer()));
   }  // end of Create

   // --------------------------------------------------------------------------

   /// <summary>Open given file for read and write</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool OpenReadWrite(TCHAR *path)
   {
      Kif::Win32::IO::File file;
      if (!file.Exists(path))
      {
         if (!Create(path))
            return(false);
      }

      // open file for read and write
      bool done = Open(path,
         GENERIC_READ | GENERIC_WRITE,        // desired access
         FILE_SHARE_READ | FILE_SHARE_WRITE,  // shared access
         OPEN_EXISTING);                      // creation disposition

      // position the cursor to the end-of-file
      if (done)
      {
         DWORD dw = SetFilePointer(hFile,0,NULL,FILE_END);
      }

      return(done);
   }  // end of OpenReadWrite

   inline bool OpenReadWrite(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(OpenReadWrite(path->GetBuffer()));
   }  // end of OpenReadWrite

   inline bool OpenReadWrite(Kif::Win32::String &path)
   {
      return(OpenReadWrite(path.GetBuffer()));
   }  // end of OpenReadWrite

   // --------------------------------------------------------------------------

   /// <summary>Open given file for read only</summary>
   /// <param name="path">file path name</param>
   /// <return>true is returned if operation was completed</returns>
   inline bool OpenRead(TCHAR *path)
   {
      // open file for read and write
      bool done = Open(path,
         GENERIC_READ,        // desired access
         FILE_SHARE_READ,     // shared access
         OPEN_EXISTING);      // creation disposition

      return(done);
   }  // end of OpenRead

   inline bool OpenRead(Kif::Win32::String *path)
   {
      if (path == NULL)
      {
         lastResult.ErrorNo = ERROR_INVALID_DATA;
         return(false);
      }
      return(OpenRead(path->GetBuffer()));
   }  // end of OpenRead

   inline bool OpenRead(Kif::Win32::String &path)
   {
      return(OpenRead(path.GetBuffer()));
   }  // end of OpenRead

   // --------------------------------------------------------------------------

   /// <summary>read data in give buffer.</summary>
   DWORD Read(Kif::Win32::String &buffer);

   /// <summary>read data in give buffer.</summary>
   char *ReadRawBuffer(DWORD bufferSizeInBytes, DWORD *bytesRead);

   /// <summary>read file and place content into a text buffer.</summary>
   static TextBuffer<char> *ReadTextFile(TCHAR *path);

   // --------------------------------------------------------------------------

   /// <summary>write data</summary>

   DWORD Write(BYTE *bytes,DWORD bytesLength);
   static inline DWORD WriteAllBytes(
      TCHAR *filePath, BYTE *bytes,DWORD bytesLength)
   {
      TextFile tf;
      tf.OpenReadWrite(filePath);
      return tf.Write(bytes, bytesLength);
   }  // end of WriteAllBytes

   /// <summary>write data to file.</summary>
   /// <remarks>the following only reads AnsiStrings (char size) strings.
   /// </remarks>
   inline DWORD TextFile::Write(char *buffer,DWORD bufferLength)
   {
      DWORD l = bufferLength*sizeof(char);
      return(Write((BYTE*)buffer,l));
   }  // end of Write

   DWORD Write(wchar_t *buffer)
   {
      if (buffer == NULL)
         return(0);
      Kif::Win32::AnsiString *as = Kif::Win32::String::ToAnsiString(buffer);
      DWORD wl = Write(as->GetBuffer(),(DWORD)as->GetLength());
      delete as;
      return(wl);
   }  // end of Write

   DWORD Write(Kif::Win32::String *buffer)
   {
      if (buffer == NULL)
         return(0);
      Kif::Win32::AnsiString *as = buffer->ToAnsiString();
      DWORD wl = Write(as->GetBuffer(),(DWORD)as->GetLength());
      delete as;
      return(wl);
   }  // end of Write

   inline DWORD Write(Kif::Win32::String &buffer)
   {  return(Write(&buffer)); }

   DWORD WriteLine(Kif::Win32::String *buffer)
   {
      DWORD wr = Write(buffer);
      char s[] = { 0x0d, 0x0a, 0x00 };
      Write(s,2);
      return(wr);
   }  // end of WriteLine

   inline DWORD WriteLine(Kif::Win32::String &buffer)
   {  return(WriteLine(&buffer)); }

   DWORD WriteLine(TCHAR *buffer)
   {
      DWORD wr = Write(buffer);
      char s[] = { 0x0d, 0x0a, 0x00 };
      Write(s,2);
      return(wr);
   }  // end of WriteLine

   // --------------------------------------------------------------------------

}  ;  // end of TextFile

}  // end of Kif::Win32::IO
}  // end of Kif::Win32
}  // end of Kif

